Conversation
Walkthrough1. GitHub Actions 워크플로우 전환. Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Suggested reviewers
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (2)
🧰 Additional context used🧠 Learnings (1)📚 Learning: 2025-11-10T01:55:03.827ZApplied to files:
🔇 Additional comments (13)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
.github/workflows/prod-cd.yml (1)
82-130: 원격 배포 SSH 스크립트의 복원력 개선이 필요합니다.현재 SSH 스크립트는 여러 단계를 순차적으로 실행하며
set -e로 에러 시 중단하도록 설정되어 있습니다. 그러나 다음과 같은 시나리오에서 개선이 필요합니다:상황별 개선 사항:
docker pull 실패 시 처리
- 현재: 에러 발생 시 그냥 중단
- 제안: 기존 이미지로 서비스 유지 또는 명확한 실패 알림
docker compose up -d 실패 시 처리
- Line 123에서 새 컨테이너 시작 실패 시, 이전 컨테이너가 이미 down된 상태
- 제안: 스크린샷 또는 파일로 이전 상태 백업 후 롤백 가능하도록 개선
Nginx 설정 적용 실패 시 처리
- Line 111의 nginx -t 검증 후 reload가 실패하면 서비스 불가
- 제안: 구 설정 백업 후 검증 실패 시 복구
아래와 같이 개선하는 것을 권장합니다:
# Nginx 설정 변경 전 백업 cp /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.backup # 새 설정 적용 sudo cp ./nginx/default.conf /etc/nginx/conf.d/default.conf # 검증 실패 시 복구 if ! sudo nginx -t; then echo "Nginx configuration test failed. Reverting..." sudo cp /etc/nginx/conf.d/default.conf.backup /etc/nginx/conf.d/default.conf sudo nginx -t exit 1 fi sudo nginx -s reload또한 Docker Compose도 이전 상태 보존을 고려하세요:
# 이전 상태 백업 docker compose -f docker-compose.prod.yml cp solid-connection-server:/var/log/spring ./logs.backup # 새 버전으로 재시작 OWNER_LOWERCASE=$OWNER_LOWERCASE IMAGE_TAG=$IMAGE_TAG_ONLY docker compose -f docker-compose.prod.yml up -d # 헬스 체크 (옵션) sleep 5 curl -f http://localhost:8080/health || { echo "Health check failed"; exit 1; }.github/workflows/dev-cd.yml (1)
118-119: Docker Compose 정리 명령어가 prod 워크플로우와 불일치합니다.현재 dev-cd.yml:
- Line 118:
docker compose -f docker-compose.dev.yml downprod-cd.yml (더 견고함):
- Line 117-120:
docker compose ... stop(graceful shutdown)docker compose ... down --remove-orphans(고아 네트워크/볼륨 정리)차이점:
- prod는 명시적으로 stop → down 순서 진행
- prod는
--remove-orphans플래그 사용 (고아 리소스 제거)- dev는 이 두 가지를 누락
이로 인해 dev 환경에서 장기 실행 후 불필요한 네트워크/볼륨이 쌓일 수 있습니다.
prod 워크플로우와 일치하도록 수정하세요:
# 6. Docker Compose 재시작 echo "Restarting Docker Compose with tag: $IMAGE_TAG_ONLY" - docker compose -f docker-compose.dev.yml down + echo "Stopping containers gracefully..." + docker compose -f docker-compose.dev.yml stop + + echo "Removing old containers and networks..." + docker compose -f docker-compose.dev.yml down --remove-orphans + + echo "Starting new containers..." OWNER_LOWERCASE=$OWNER_LOWERCASE IMAGE_TAG=$IMAGE_TAG_ONLY docker compose -f docker-compose.dev.yml up -d
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
.github/workflows/dev-cd.yml(2 hunks).github/workflows/prod-cd.yml(1 hunks)Dockerfile(2 hunks)docker-compose.dev.yml(2 hunks)docker-compose.prod.yml(1 hunks)src/main/resources/secret(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-25T10:59:42.734Z
Learnt from: whqtker
Repo: solid-connection/solid-connect-server PR: 481
File: docs/infra-config/nginx.conf:36-36
Timestamp: 2025-08-25T10:59:42.734Z
Learning: When using network_mode: host in Docker Compose, containers share the host's network namespace, so nginx proxy_pass should target localhost:PORT instead of container service names like solid-connection-server:PORT.
Applied to files:
docker-compose.prod.yml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (6)
src/main/resources/secret (1)
1-1: 서브모듈 포인터 업데이트 확인 필요합니다.
src/main/resources/secret서브모듈이ae3e90ef→b2fb5167로 업데이트되었습니다. 다음 사항을 확인해 주세요:
- 변경 내용 검증: 새 커밋 (
b2fb5167)에서 어떤 변경사항이 발생했는지 확인 필요- CD 리팩터링 연관성: 현재 PR의 CD 워크플로우 개선(GitHub Actions → GHCR → docker-compose)과 이 서브모듈 업데이트의 관계 확인
- 보안 영향도:
secret디렉토리 특성상 민감한 정보 포함 여부 및 변경에 따른 보안 영향 검토이 서브모듈이 실제로 이 PR의 범위에 포함되어야 하는지, 아니면 별도로 관리되어야 하는지 명확히 해 주시기 바랍니다.
docker-compose.dev.yml (1)
21-21: 환경 변수 전달 방식 확인이 필요합니다.Line 21의 이미지 참조가
OWNER_LOWERCASE와IMAGE_TAG환경 변수에 의존하고 있습니다. 워크플로우에서OWNER_LOWERCASE=$OWNER_LOWERCASE IMAGE_TAG=$IMAGE_TAG_ONLY docker compose로 명시적으로 전달하고 있으므로 동작하겠지만, 로컬 개발 환경에서도 이 변수들을 설정하고 실행해야 합니다.로컬에서 수동 테스트 시 아래 명령어로 실행되는지 확인하세요:
export OWNER_LOWERCASE=<your-org> export IMAGE_TAG=<tag-or-leave-for-latest> docker compose -f docker-compose.dev.yml up -ddocker-compose.prod.yml (1)
21-21: 환경 변수 전달 방식 일관성 유지 필요합니다.docker-compose.dev.yml과 마찬가지로 Line 21의 이미지 참조는
OWNER_LOWERCASE와IMAGE_TAG환경 변수에 의존합니다. 워크플로우에서 올바르게 전달되고 있으나, 배포 전 로컬 테스트 시에도 동일한 방식으로 환경 변수를 설정해야 합니다.추가적으로, nginx 설정(prod-cd.yml의 라인 107~112)이 이 compose 파일 외부에서 관리되므로, nginx 컨테이너가 bridge network을 사용하는 경우
proxy_pass http://solid-connection-server:8080형식으로 서비스명을 사용해야 함을 확인하세요.Dockerfile (1)
2-2: Base image 변경이 적절합니다.OpenJDK는 더 이상 유지보수되지 않으며, Eclipse Temurin은 공식 대체 이미지입니다. 변경 자체는 명확하고 문제없어 보입니다.
다만 한 가지 검증 항목:
- 빌드 플랫폼 호환성: 워크플로우에서
linux/arm64플랫폼을 지정하고 있습니다. Eclipse Temurin:17-jdk가 이 플랫폼에서 정상 작동하는지 확인하세요..github/workflows/prod-cd.yml (1)
106-112: Nginx 설정 변경 시 권한 문제 검토가 필요합니다.원격 SSH 명령어에서 Nginx 설정을 다음과 같이 처리하고 있습니다:
- 로컬에서 nginx.prod.conf를 scp로 전송 (Line 76)
- 원격에서 ./nginx/default.conf로 이동 (Line 107)
- sudo로 /etc/nginx/conf.d/default.conf에 복사 (Line 110)
- sudo nginx -t 및 sudo nginx -s reload 실행 (Lines 111-112)
문제점:
sudo명령어 실행 시 비밀번호 입력 없이 동작해야 하는데, 배포 키 기반 SSH에서 이것이 보장되는지 확인 필요- Nginx 설정 검증 실패 시 에러 처리 미흡 (set -e가 있으므로 중단되지만, 롤백 로직 없음)
다음을 확인하세요:
- 배포 서버의 sudoers 파일에서 해당 사용자(
${{ secrets.USERNAME }})가 비밀번호 없이 nginx 명령어를 실행할 수 있도록 설정되었는지 확인- nginx -t 검증 실패 시 이전 설정으로 복구하는 로직 추가 검토
.github/workflows/dev-cd.yml (1)
130-139: 이미지 보관 정책의 이미지명을 검토하세요.Line 134에서
image-names: solid-connection로 지정되어 있으나, 실제 푸시된 이미지명은:
- Line 54:
ghcr.io/${OWNER_LOWERCASE}/solid-connection-dev또한 prod-cd.yml의 보관 정책과도 불일치:
- prod:
image-names: solid-connection-prod- dev:
image-names: solid-connection다음을 확인하고 수정하세요:
- 실제 GHCR에 푸시되는 이미지명 확인
- 보관 정책의 이미지명을 정확하게 매칭:
- image-names: solid-connection + image-names: solid-connection-dev또는 조직 수준의 보관 정책을 사용하려면 와일드카드 지원 여부 확인 필요.
.github/workflows/dev-cd.yml
Outdated
| export FULL_IMAGE_NAME="ghcr.io/${OWNER_LOWERCASE}/solid-connection-dev:${IMAGE_TAG_ONLY}" | ||
|
|
||
| # 2. 서버가 GHCR에 로그인 (pull 받기 위해) | ||
| echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin |
There was a problem hiding this comment.
GHCR 로그인 시 사용자명 대소문자 불일치 문제가 있습니다.
dev-cd.yml도 prod-cd.yml과 동일한 문제가 있습니다.
Line 100에서 docker login 시 사용자명으로 ${{ github.repository_owner }}를 사용하고 있으나, 이미지 태그는 소문자로 변환되어 있습니다:
- Line 52:
OWNER_LOWERCASE=$(echo ... | tr '[:upper:]' '[:lower:]') - Line 54: 이미지명에 OWNER_LOWERCASE 사용
GitHub 저장소 소유자명에 대문자가 있으면 로그인 실패 또는 권한 오류 발생 가능성이 있습니다.
수정 방법:
# 2. 서버가 GHCR에 로그인 (pull 받기 위해)
- echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin
+ OWNER_LOWERCASE=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')
+ echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${OWNER_LOWERCASE} --password-stdin📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin | |
| OWNER_LOWERCASE=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]') | |
| echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${OWNER_LOWERCASE} --password-stdin |
🤖 Prompt for AI Agents
.github/workflows/dev-cd.yml around line 100: the docker login uses ${{
github.repository_owner }} which may contain uppercase letters while the image
tag and OWNER_LOWERCASE are used elsewhere, causing GHCR auth failures; change
the login username to the already-computed OWNER_LOWERCASE variable (or compute
a lowercase owner just before login) so the docker login user matches the
lowercase image namespace, and apply the same change in prod-cd.yml.
There was a problem hiding this comment.
이전에 lower_case로 통일하도록 이미지 메타데이터 정의 스텝에서 전처리를 해두었기에 문제가 나지 않을 것 같은데?
심지어 내 닉네임이 Hexeong인데, fork 레포에서 깃헙 액션을 실행시켰을 때에 문제가 발생하지 않았었어
There was a problem hiding this comment.
맞습니다! 제가 잘못 지적했네요. 죄송합니다. 🙇
-
Docker/GHCR 로그인은 사용자명 대소문자를 구분하지 않습니다.
- Line 100의
docker login ghcr.io -u ${{ github.repository_owner }}는Hexeong이든hexeong이든 정상적으로 인증됩니다.
- Line 100의
-
이미지 경로는 올바르게 소문자를 사용하고 있습니다.
- Line 95에서
OWNER_LOWERCASE를 재계산하고 - Line 97에서
FULL_IMAGE_NAME에 소문자 버전을 사용하여 - Line 103의
docker pull이 정상 작동합니다.
- Line 95에서
실제 테스트에서 문제가 없었다는 것이 이를 증명하네요. 불필요한 수정 제안을 드려 혼란을 드려 죄송합니다!
| - name: Log in to GitHub Container Registry (GHCR) | ||
| uses: docker/login-action@v3 | ||
| with: | ||
| registry: ghcr.io | ||
| username: ${{ github.repository_owner }} | ||
| password: ${{ secrets.GITHUB_TOKEN }} |
There was a problem hiding this comment.
GHCR 로그인 시 사용자명 대소문자 불일치 문제가 있습니다.
워크플로우를 자세히 보면:
- GitHub Actions에서 GHCR 로그인 (Line 44):
${{ github.repository_owner }}(원본 대소문자 유지) - 이미지 메타데이터 정의 (Lines 51-54):
OWNER_LOWERCASE=$(echo ... | tr '[:upper:]' '[:lower:]')로 소문자 변환 - 원격 서버 GHCR 로그인 (Line 98):
${{ github.repository_owner }}(원본 대소문자 유지)
문제: GitHub 저장소 소유자명이 대문자를 포함하면, docker pull 시 이미지명과 로그인 사용자명의 대소문자 불일치로 인증 오류가 발생할 수 있습니다.
아래와 같이 수정하세요:
# 2. 서버가 GHCR에 로그인 (pull 받기 위해)
- echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin
+ OWNER_LOWERCASE=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')
+ echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${OWNER_LOWERCASE} --password-stdinAlso applies to: 98-100
🤖 Prompt for AI Agents
.github/workflows/prod-cd.yml lines 40-45 (also applies to lines 98-100): GHCR
login uses `${{ github.repository_owner }}` which can contain uppercase letters
causing mismatch with the image names that are converted to lowercase; update
the workflow to pass a lowercased owner username to docker/login-action (use the
same lowercase transformation used for OWNER_LOWERCASE) so both GHCR login steps
use the lowercase repository owner; ensure the environment variable or step
output holding the lowercase owner is referenced in both login steps.
There was a problem hiding this comment.
레지스트리 경로명은 항상 소문자로 유지되기에 repository_owner가 대문자가 포함되어 있어도 이후에 문제가 되지 않아!
There was a problem hiding this comment.
@Hexeong, 설명 감사합니다! GHCR의 인증 과정에서 사용자명은 대소문자를 구분하지 않고, 레지스트리 경로는 자동으로 소문자로 정규화되는 점을 확인해주셨네요. 제가 너무 신중하게 접근했습니다. 현재 구현이 문제없이 작동하겠네요! 👍
✏️ Learnings added
Learnt from: Hexeong
Repo: solid-connection/solid-connect-server PR: 552
File: .github/workflows/prod-cd.yml:40-45
Timestamp: 2025-11-10T01:55:03.812Z
Learning: GHCR (GitHub Container Registry)에서는 docker login 시 사용자명의 대소문자를 구분하지 않으며, 레지스트리 경로명은 항상 소문자로 정규화됩니다. 따라서 `github.repository_owner`를 그대로 사용해도 이미지 경로와의 대소문자 불일치 문제가 발생하지 않습니다.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
| - name: Clean up old image versions from GHCR | ||
| if: success() | ||
| uses: snok/container-retention-policy@v2 | ||
| with: | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| image-names: solid-connection-prod | ||
| delete-untagged: true | ||
| keep-n-tags: 5 | ||
| account-type: org | ||
| org-name: ${{ github.repository_owner }} |
There was a problem hiding this comment.
이미지 보관 정책의 이미지명 불일치가 있습니다.
Line 138에서 image-names: solid-connection-prod로 지정되어 있으나, 실제 푸시된 이미지는:
- Line 53:
ghcr.io/${OWNER_LOWERCASE}/solid-connection-server
동일하게 dev-cd.yml (Line 134)는 image-names: solid-connection로 지정되어 있습니다.
두 워크플로우 간 네이밍 정책이 일관되지 않습니다. 정리해야 할 항목:
- prod 워크플로우:
solid-connection-prodvs 실제 푸시 이미지명solid-connection-server - dev 워크플로우:
solid-connectionvs 실제 푸시 이미지명solid-connection-dev
이미지 보관 정책이 정확한 이미지명과 일치하도록 수정하세요:
- name: Clean up old image versions from GHCR
...
with:
token: ${{ secrets.GITHUB_TOKEN }}
- image-names: solid-connection-prod
+ image-names: solid-connection-server
delete-untagged: true
keep-n-tags: 5
account-type: org
org-name: ${{ github.repository_owner }}
cut-off: '7 days ago UTC'📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - name: Clean up old image versions from GHCR | |
| if: success() | |
| uses: snok/container-retention-policy@v2 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| image-names: solid-connection-prod | |
| delete-untagged: true | |
| keep-n-tags: 5 | |
| account-type: org | |
| org-name: ${{ github.repository_owner }} | |
| - name: Clean up old image versions from GHCR | |
| if: success() | |
| uses: snok/container-retention-policy@v2 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| image-names: solid-connection-server | |
| delete-untagged: true | |
| keep-n-tags: 5 | |
| account-type: org | |
| org-name: ${{ github.repository_owner }} |
🤖 Prompt for AI Agents
In .github/workflows/prod-cd.yml around lines 133-142 the image-names value is
set to "solid-connection-prod" but the pushed image is
"ghcr.io/${OWNER_LOWERCASE}/solid-connection-server" (see push at line 53);
update image-names to "solid-connection-server". Also update the dev workflow
(.github/workflows/dev-cd.yml around line 134) where image-names is
"solid-connection" to the actual pushed name "solid-connection-dev". Ensure the
container-retention-policy steps in both workflows use the exact image names
that are pushed to GHCR.
Gyuhyeok99
left a comment
There was a problem hiding this comment.
하지만, prod의 경우 release 버전으로 이미지가 관리될 수 있다 보니, 이미지 태그에 대한 내용을 스크립트 상에 하드코딩할 수 없는 상태입니다.
이게 어떤 말씀이신가요~?? release tag 활용하면 되는 건 아닌가요!?
.github/workflows/prod-cd.yml
Outdated
| sudo nginx -t | ||
| sudo nginx -s reload | ||
| scp -i deploy_key.pem \ | ||
| -o StrictHostKeyChecking:no \ |
There was a problem hiding this comment.
@coderabbitai
StrictHostKeyChecking:no
StrictHostKeyChecking=no
이거 문법 뭐가 맞아?
There was a problem hiding this comment.
올바른 문법은 StrictHostKeyChecking=no 입니다 (등호 사용).
SSH 옵션은 -o option=value 형식을 사용해야 합니다. 콜론(:)이 아니라 등호(=)를 사용해야 합니다.
현재 파일에서 두 곳 모두 수정이 필요합니다:
-
Line 71 (scp 명령어):
scp -i deploy_key.pem \ -o StrictHostKeyChecking=no \
-
Line 83 (ssh 명령어):
ssh -i deploy_key_ssh.pem \ -o StrictHostKeyChecking=no \
콜론을 사용하면 SSH가 옵션을 올바르게 인식하지 못할 수 있습니다.
There was a problem hiding this comment.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
아하 제가 릴리즈 기능을 써본 적이 없어서 몰랐던 것 같습니다;; 이 방식으로 배포할 경우 |
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (2)
.github/workflows/prod-cd.yml (2)
40-45:⚠️ GHCR 로그인 시 소유자명 대소문자 불일치 문제 (이전 리뷰의 미해결 항목)앞선 리뷰에서 지적되었던 문제가 여전히 남아 있습니다.
문제:
- Line 44의 GHCR 로그인:
${{ github.repository_owner }}(원본 대소문자 유지)- Line 53의 이미지명:
ghcr.io/${OWNER_LOWERCASE}/solid-connection-server(소문자 변환)리포지토리 소유자명에 대문자가 포함되면, 로그인 사용자명과 이미지명의 대소문자 불일치로 인증 오류가 발생합니다.
수정:
- name: Log in to GitHub Container Registry (GHCR) uses: docker/login-action@v3 with: registry: ghcr.io - username: ${{ github.repository_owner }} + username: ${{ steps.image_meta.outputs.owner_lowercase }} password: ${{ secrets.GITHUB_TOKEN }}그리고 Line 48-54의 메타데이터 정의 단계에 다음 줄을 추가하세요:
- name: Define image name and tag id: image_meta run: | OWNER_LOWERCASE=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]') + echo "owner_lowercase=${OWNER_LOWERCASE}" >> $GITHUB_OUTPUT IMAGE_TAG=$(date +'%Y%m%d-%H%M%S') echo "image_name=ghcr.io/${OWNER_LOWERCASE}/solid-connection-server" >> $GITHUB_OUTPUT echo "image_tag=${IMAGE_TAG}" >> $GITHUB_OUTPUT
98-98:⚠️ 원격 서버의 GHCR 로그인에서도 소유자명 대소문자 불일치 (이전 리뷰의 미해결 항목)Line 40-45의 GHCR 로그인 문제와 동일하게, 원격 서버에서의 docker login 명령어에서도 대소문자 불일치가 발생합니다.
문제:
- Line 93:
export OWNER_LOWERCASE=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')로 소문자 변수 생성- Line 98:
docker login ghcr.io -u ${{ github.repository_owner }}(원본 대소문자 사용)변수가 정의되었으므로 일관성 있게 사용하세요.
수정:
# 2. 서버가 GHCR에 로그인 (pull 받기 위해) - echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin + echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${OWNER_LOWERCASE} --password-stdin
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
.github/workflows/prod-cd.yml(1 hunks)
🔇 Additional comments (4)
.github/workflows/prod-cd.yml (4)
1-34: 기본 설정 단계가 잘 구성되었습니다.Java, Gradle 설정과 초기 빌드 단계가 명확하게 작성되었습니다. 특히 submodule 체크아웃과 Gradle wrapper 권한 설정이 적절합니다.
56-65: Docker 빌드 및 푸시 구성이 잘 설계되었습니다.메타데이터를 올바르게 활용하고, 레지스트리 캐시를 통해 빌드 성능 최적화를 구현한 점이 좋습니다. 멀티 플랫폼 지원도 명시되어 있습니다.
100-130: 배포 로직이 견고하게 구성되었습니다.이미지 pull부터 Nginx 재시작, Docker Compose 재시작, 정리까지의 단계가 명확하고,
set -e를 통한 에러 처리와 graceful shutdown 로직이 좋습니다. 위의 문법 오류들을 수정하면 배포 흐름이 안정적으로 작동할 것입니다.
132-143: GHCR 이미지 정리 정책이 올바르게 수정되었습니다. ✅이전 리뷰에서 지적했던 image-names 불일치 문제(solid-connection-prod → solid-connection-server)가 이미 반영되었습니다. 실제 푸시된 이미지명과 일치하며, 5개 태그 유지 및 7일 이상 된 이미지 정리 정책이 적절합니다.
Gyuhyeok99
left a comment
There was a problem hiding this comment.
이미지를 pull하는 방식으로 잘 개선해주신 거 같네요! 고생하셨습니다!
길게 잡고 점진적으로 개선해나가봐요!
.github/workflows/dev-cd.yml
Outdated
| keep-n-tags: 5 | ||
| account-type: org | ||
| org-name: ${{ github.repository_owner }} | ||
| cut-off: '7 days ago UTC' No newline at end of file |
.github/workflows/prod-cd.yml
Outdated
| keep-n-tags: 5 | ||
| account-type: org | ||
| org-name: ${{ github.repository_owner }} | ||
| cut-off: '7 days ago UTC' No newline at end of file |
Dockerfile
Outdated
|
|
||
| # 볼륨 설정 | ||
| VOLUME /tmp | ||
| VOLUME /tmp No newline at end of file |
docker-compose.dev.yml
Outdated
| - ./docs/infra-config/config.alloy:/etc/alloy/config.alloy:ro | ||
| environment: | ||
| - ALLOY_ENV=dev | ||
| - ALLOY_ENV=dev No newline at end of file |
| - name: Define image name and tag | ||
| id: image_meta | ||
| run: | | ||
| OWNER_LOWERCASE=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]') |
There was a problem hiding this comment.
github.repository_owner 로 설정하면 레포 소유자 이름(e.g. whqtker)으로 고정되는 건가요 ? 만약 그렇다면, solid-connection 과 같이 사용자에 종속되지 않는 이름으로 설정하는 게 좋을 거 같습니다 !
There was a problem hiding this comment.
Organization에 속한 레포의 워크플로우 실행의 경우 github.repository_owner은 Organization 이름인 solid-connection이 됩니다! 때문에 사용자 이름으로 종속되지는 않아 해당 문제는 없을 것 같아요!
.github/workflows/dev-cd.yml
Outdated
| uses: snok/container-retention-policy@v2 | ||
| with: | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| image-names: solid-connection |
There was a problem hiding this comment.
image-names 를 solid-connection-dev 로 설정해야 할 듯 합니다 ~!
어 그럼 이부분도 GHCR Clean up 작업처럼 하나 추가해서 최신 이미지 10개만 유지하게 할까요?? 어떻게 생각하시나용 @whqtker |
Gyuhyeok99
left a comment
There was a problem hiding this comment.
이번 pr만큼은 수연님도 리뷰해주시면 좋겠습니다~
Hexeong
left a comment
There was a problem hiding this comment.
반영사항들 반영해두었습니다! pending 처리되어있던 걸 제가 늦게 확인했네요;; 빠르게 stage 인스턴스에 대해서도 old 이미지를 지우는 step도 추가해두겠습니다!
.github/workflows/dev-cd.yml
Outdated
| export FULL_IMAGE_NAME="ghcr.io/${OWNER_LOWERCASE}/solid-connection-dev:${IMAGE_TAG_ONLY}" | ||
|
|
||
| # 2. 서버가 GHCR에 로그인 (pull 받기 위해) | ||
| echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin |
There was a problem hiding this comment.
이전에 lower_case로 통일하도록 이미지 메타데이터 정의 스텝에서 전처리를 해두었기에 문제가 나지 않을 것 같은데?
심지어 내 닉네임이 Hexeong인데, fork 레포에서 깃헙 액션을 실행시켰을 때에 문제가 발생하지 않았었어
| - name: Clean up old image versions from GHCR | ||
| if: success() | ||
| uses: snok/container-retention-policy@v2 | ||
| with: | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| image-names: solid-connection-prod | ||
| delete-untagged: true | ||
| keep-n-tags: 5 | ||
| account-type: org | ||
| org-name: ${{ github.repository_owner }} |
| - name: Log in to GitHub Container Registry (GHCR) | ||
| uses: docker/login-action@v3 | ||
| with: | ||
| registry: ghcr.io | ||
| username: ${{ github.repository_owner }} | ||
| password: ${{ secrets.GITHUB_TOKEN }} |
There was a problem hiding this comment.
레지스트리 경로명은 항상 소문자로 유지되기에 repository_owner가 대문자가 포함되어 있어도 이후에 문제가 되지 않아!
.github/workflows/prod-cd.yml
Outdated
| sudo nginx -t | ||
| sudo nginx -s reload | ||
| scp -i deploy_key.pem \ | ||
| -o StrictHostKeyChecking:no \ |
| - name: Define image name and tag | ||
| id: image_meta | ||
| run: | | ||
| OWNER_LOWERCASE=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]') |
There was a problem hiding this comment.
Organization에 속한 레포의 워크플로우 실행의 경우 github.repository_owner은 Organization 이름인 solid-connection이 됩니다! 때문에 사용자 이름으로 종속되지는 않아 해당 문제는 없을 것 같아요!
.github/workflows/prod-cd.yml
Outdated
| keep-n-tags: 5 | ||
| account-type: org | ||
| org-name: ${{ github.repository_owner }} | ||
| cut-off: '7 days ago UTC' No newline at end of file |
Dockerfile
Outdated
|
|
||
| # 볼륨 설정 | ||
| VOLUME /tmp | ||
| VOLUME /tmp No newline at end of file |
docker-compose.dev.yml
Outdated
| - ./docs/infra-config/config.alloy:/etc/alloy/config.alloy:ro | ||
| environment: | ||
| - ALLOY_ENV=dev | ||
| - ALLOY_ENV=dev No newline at end of file |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
.github/workflows/dev-cd.yml (3)
69-80: SCP 전송 시 에러 처리 추가 권장.현재 설정 파일 전송 단계에서 scp 명령이 실패해도 워크플로우가 계속 진행됩니다. 예를 들어, 파일이 존재하지 않거나 네트워크 오류가 발생할 경우를 대비하세요.
다음과 같이 개선하면 실패 시 명확히 감지할 수 있습니다:
- name: Copy config files to remote run: | echo "${{ secrets.DEV_PRIVATE_KEY }}" > deploy_key.pem chmod 600 deploy_key.pem + set -e # 에러 발생 시 즉시 중단 + scp -i deploy_key.pem \ -o StrictHostKeyChecking=no \ ./docker-compose.dev.yml \ ./docs/infra-config/config.alloy \ ./docs/infra-config/nginx.dev.conf \ ${{ secrets.DEV_USERNAME }}@${{ secrets.DEV_HOST }}:/home/${{ secrets.DEV_USERNAME }}/solid-connection-dev/
118-119: docker compose 명령어 실행 시 환경 변수 설정 방식 정리.현재 Line 119에서:
OWNER_LOWERCASE=$OWNER_LOWERCASE IMAGE_TAG=$IMAGE_TAG_ONLY docker compose -f docker-compose.dev.yml up -d이 패턴은 작동하지만,
OWNER_LOWERCASE가 Line 95에서 이미 export되었다면 불필요한 중복입니다. 일관성을 위해 다음 중 하나로 정리하세요:옵션 1: 환경 변수를 명시적으로 선언하고 재사용
export OWNER_LOWERCASE=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]') export IMAGE_TAG_ONLY=${{ steps.image_meta.outputs.image_tag }} # ... docker compose -f docker-compose.dev.yml up -d옵션 2: 매번 인라인으로 설정 (현재 방식이지만 정리)
IMAGE_TAG=${{ steps.image_meta.outputs.image_tag }} \ OWNER_LOWERCASE=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]') \ docker compose -f docker-compose.dev.yml up -d
129-132: 오래된 이미지 정리 로직이 정상 작동하는지 검증 권장.Line 129-132의 이미지 정리 로직은 수동으로 태그를 정렬하고 삭제합니다:
docker images "${IMAGE_NAME_BASE}" --format "{{.Tag}}" | \ sort -r | \ tail -n +6 | \ xargs -I {} docker rmi "${IMAGE_NAME_BASE}:{}" || true주의할 점:
docker images출력에<none>태그가 포함될 수 있으며, 이는 정렬 순서에 영향을 미칠 수 있습니다.- 태그가 6개 미만이면 아무것도 삭제되지 않습니다 (의도한 동작이라면 문제 없음).
|| true로 인해 삭제 실패가 무시되므로, 실제 오류를 인지하기 어려울 수 있습니다.개선 제안:
GHCR의 자동 정리 정책(Line 137-147, 최신 5개 유지)과의 일관성을 위해, 로컬 환경에서도 같은 개수를 유지하되, 더 명확한 로직을 고려하세요:
docker images "${IMAGE_NAME_BASE}" --format "table {{.Repository}}:{{.Tag}}\t{{.CreatedAt}}" | \ tail -n +2 | \ sort -k2 -r | \ tail -n +6 | \ awk '{print $1}' | \ xargs -r docker rmi또는 snok/container-retention-policy 같은 로컬 도구도 검토해볼 가치가 있습니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
.github/workflows/dev-cd.yml(2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-10T01:55:03.812Z
Learnt from: Hexeong
Repo: solid-connection/solid-connect-server PR: 552
File: .github/workflows/prod-cd.yml:40-45
Timestamp: 2025-11-10T01:55:03.812Z
Learning: GHCR (GitHub Container Registry)에서는 docker login 시 사용자명의 대소문자를 구분하지 않으며, 레지스트리 경로명은 항상 소문자로 정규화됩니다. 따라서 `github.repository_owner`를 그대로 사용해도 이미지 경로와의 대소문자 불일치 문제가 발생하지 않습니다.
Applied to files:
.github/workflows/dev-cd.yml
🔇 Additional comments (2)
.github/workflows/dev-cd.yml (2)
47-55: 이미지 메타데이터 정의 로직이 명확하고 효율적입니다.이미지 이름과 태그를 GitHub Actions Output으로 미리 정의하여 여러 단계에서 재사용할 수 있게 설계된 점이 좋습니다. 특히:
- OWNER_LOWERCASE로 소문자 정규화: GHCR 이미지명 규칙 준수 ✓
- 타임스탬프 기반 태깅(YYYYMMDD-HHMMSS): 버전 추적 명확함 ✓
- 이미지명 포맷 표준화: 코드 가독성 향상 ✓
137-147: GHCR 자동 정리 정책이 체계적으로 구성되었습니다.snok/container-retention-policy를 활용한 정책이 명확합니다:
- 태그 없는 이미지 자동 삭제 (delete-untagged: true)
- 최신 5개 버전 유지 (keep-n-tags: 5)
- 7일 이상 오래된 버전 정리 (cut-off: 7 days ago)
- 성공 시에만 실행 (if: success()) — 안정성 고려 ✓
로컬 정리 정책(Line 129-132)과도 일관성이 있어, 스토리지 관리가 예측 가능합니다.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
.github/workflows/dev-cd.yml (1)
137-147: GHCR 이미지 정리 정책과 로컬 호스트 정리 정책의 일관성이 확인됩니다.GHCR에서 최신 5개 태그를 유지(
keep-n-tags: 5)하고, Line 131에서 로컬 호스트에서도 동일하게 최신 5개를 유지하는 방식으로 정책이 일관되어 있습니다.delete-untagged: true로 미태그 이미지도 정리하므로 레지스트리 저장소 효율이 좋습니다.다만, 다음 사항을 확인해주세요:
- 정기적 정리 스케줄: 현재 구조에서는 성공적인 배포 시에만 정리가 실행됩니다(
if: success()). 배포가 자주 이루어지지 않는 기간이 있다면 저장소가 누적될 수 있으니, 필요시 별도의 정기 정리 워크플로우(예: 주 1회 스케줄 실행)도 고려해보세요.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
.github/workflows/dev-cd.yml(2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-10T01:55:03.812Z
Learnt from: Hexeong
Repo: solid-connection/solid-connect-server PR: 552
File: .github/workflows/prod-cd.yml:40-45
Timestamp: 2025-11-10T01:55:03.812Z
Learning: GHCR (GitHub Container Registry)에서는 docker login 시 사용자명의 대소문자를 구분하지 않으며, 레지스트리 경로명은 항상 소문자로 정규화됩니다. 따라서 `github.repository_owner`를 그대로 사용해도 이미지 경로와의 대소문자 불일치 문제가 발생하지 않습니다.
Applied to files:
.github/workflows/dev-cd.yml
🔇 Additional comments (3)
.github/workflows/dev-cd.yml (3)
47-67: 이미지 메타데이터 정의 및 빌드 캐시 전략이 명확합니다.이미지명과 태그를 명시적으로 정의하고, Docker BuildX의 레지스트리 캐시(
type=registry)를 활용해 빌드 성능을 개선하는 구조가 좋습니다. 타임스탬프 기반 태그(YYYYMMDD-HHMMSS)는 dev 환경에서 이미지 버전 추적에 효과적입니다.
87-135: SSH 배포 스크립트의 변수 관리와 함께 일관성 개선을 제안합니다.현재 구조는 다음과 같은 점에서 정상 작동하지만, 명확성을 위해 몇 가지 정리를 제안합니다:
로그인 사용자명 일관성
- Line 95에서
OWNER_LOWERCASE를 계산하지만, Line 100의docker login에서는 여전히${{ github.repository_owner }}를 사용 중입니다.- 비록 GHCR에서 대소문자를 구분하지 않지만, 코드의 일관성과 가독성 차원에서 이미 계산한
OWNER_LOWERCASE변수를 사용하는 것이 좋습니다.환경 변수 전달 방식
- Line 119의
IMAGE_TAG=$IMAGE_TAG_ONLY docker compose ...는 정상 작동합니다(IMAGE_TAG환경변수가 해당 명령 실행 시에만 유효).- 다만,
OWNER_LOWERCASE는 Line 95에서 이미 export되었으므로, docker-compose.dev.yml이 두 변수를 모두 필요로 한다면 현재 구조로 충분합니다.오래된 이미지 정리 로직 확인
- Lines 129-132에서
sort -r | tail -n +6으로 최신 5개를 제외한 나머지를 삭제하는 로직은 정확합니다.- 다만, 타임스탬프 기반 정렬(이미지 태그 문자열)과 실제 생성 시간의 순서가 일치하는지 확인이 필요합니다. (현재 YYYYMMDD-HHMMSS 형식이므로 문자열 정렬과 시간 순서가 일치함)
다음 개선안을 고려해주세요:
# 2. 서버가 GHCR에 로그인 (pull 받기 위해) - echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin + echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${OWNER_LOWERCASE} --password-stdin이렇게 하면 로그인 사용자명이 이미지명 계산 부분과 완전히 일치하게 됩니다.
69-80: 설정 파일 전송 단계가 효율적으로 통합되었습니다.기존의 개별 파일 전송 방식에서 하나의 scp 명령으로 여러 파일을 전송하도록 통합되어, 워크플로우 단계가 간결해졌습니다. SSH 보안 설정(StrictHostKeyChecking=no, 권한 600)도 적절합니다.
lsy1307
left a comment
There was a problem hiding this comment.
개인적으로 on push 방식으로 release태그를 사용하는 게 배포 자동화 면에서 이점이 있다고 생각합니당
.github/workflows/dev-cd.yml
Outdated
| echo "${{ secrets.DEV_PRIVATE_KEY }}" > deploy_key_ssh.pem | ||
| chmod 600 deploy_key_ssh.pem |
There was a problem hiding this comment.
위에서 생성한 key를 그대로 사용해도 되지 않나요..?
There was a problem hiding this comment.
이름도 바꿔주셔야 할 것 같아요! deploy_key.pem으로 저장이 되었는데 deploy_key_ssh.pem을 사용하고 있습니당
.github/workflows/dev-cd.yml
Outdated
| export FULL_IMAGE_NAME="ghcr.io/${OWNER_LOWERCASE}/solid-connection-dev:${IMAGE_TAG_ONLY}" | ||
|
|
||
| # 2. 서버가 GHCR에 로그인 (pull 받기 위해) | ||
| echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin |
There was a problem hiding this comment.
지금 쓰기가 가능한 토큰이 서버로 전송되는데 보안상 취약하지 않을까요...? 읽기 전용 토큰을 따로 발급해서 사용하는 게 좋아보입니당
There was a problem hiding this comment.
SSH를 통해 GHCR에 접근하는 이 방식을 적용하려면, SUBMODULE_ACCESS_TOKEN처럼 Fine-grained Token을 사용하는 것이 보안상 가장 좋다고 생각합니다!
하지만 이 방식을 사용하려면 GHCR 읽기 권한이 있는 분이 직접 토큰을 발급해야 하는데, 이는 특정 계정에 파이프라인이 의존하게 되는 문제가 있어 망설여졌습니다.
그래서 일단은 임시로 GITHUB_TOKEN을 사용하는 방식을 적용했습니다만, 혹시 이 '개인 종속성' 문제를 해결할 더 좋은 방법이 있다면 의견 부탁드립니다! @lsy1307
There was a problem hiding this comment.
machine user 개념으로 CI/CD용 계정을 따로 만들어서 사용하는 건 어떨까요? Github Docs에도 나와있는 내용입니다!
참고 : https://docs.github.com/en/get-started/learning-about-github/types-of-github-accounts#user-accounts
There was a problem hiding this comment.
machine user 대신 최근 Github 추천하는 방식인 Github App을 사용해서 Repository에서 임시 토큰을 발급할 수 있도록 개선했습니다! 해당 문제는 해결된 것 같아요!
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
.github/workflows/dev-cd.yml (1)
83-132: SSH 스크립트 내 환경 변수 정의 정리 제안.현재 설계:
- 라인 52–55에서 GitHub Actions 컨텍스트에서
OWNER_LOWERCASE와IMAGE_TAG생성- 라인 92–94에서 SSH 스크립트 내부에서 동일한 값을 재계산
재계산은 작동하지만 불필요한 중복입니다. GitHub Actions 출력값이 이미 SSH 스크립트 내
${{ steps.image_meta.outputs.* }}구문으로 전달되므로, 아래처럼 간소화할 수 있습니다:export OWNER_LOWERCASE=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]') export IMAGE_TAG_ONLY=${{ steps.image_meta.outputs.image_tag }} export FULL_IMAGE_NAME="ghcr.io/${OWNER_LOWERCASE}/solid-connection-dev:${IMAGE_TAG_ONLY}"이미 export된
OWNER_LOWERCASE를 재계산할 필요 없이 일관성 있게 사용할 수 있으며, 라인 116의IMAGE_TAG=$IMAGE_TAG_ONLY docker compose...부분도 명확해집니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
.github/workflows/dev-cd.yml(2 hunks)src/main/resources/secret(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- src/main/resources/secret
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-10T01:55:03.812Z
Learnt from: Hexeong
Repo: solid-connection/solid-connect-server PR: 552
File: .github/workflows/prod-cd.yml:40-45
Timestamp: 2025-11-10T01:55:03.812Z
Learning: GHCR (GitHub Container Registry)에서는 docker login 시 사용자명의 대소문자를 구분하지 않으며, 레지스트리 경로명은 항상 소문자로 정규화됩니다. 따라서 `github.repository_owner`를 그대로 사용해도 이미지 경로와의 대소문자 불일치 문제가 발생하지 않습니다.
Applied to files:
.github/workflows/dev-cd.yml
🔇 Additional comments (4)
.github/workflows/dev-cd.yml (4)
11-33: 좋은 권한 설정과 표준 Gradle 스택.권한에
packages: write를 추가했고, 최신 공식 Gradle 액션(v3)을 사용하여 정확하게 구성되었습니다. JDK 17 temurin 배포판도 Dockerfile 변경과 일치합니다.
35-67: Docker 빌드·푸시 단계가 잘 설계됨.Docker Buildx 멀티 아키텍처 지원, GHCR 로그인, 이미지 메타데이터(이름·태그) 사전 정의, 레지스트리 캐시 전략까지 모두 CD 성능 개선 목표와 일치합니다. 특히 buildcache 태그를 활용한 레이어 캐싱은 반복 배포 시 빌드 시간 단축에 효과적입니다.
103-132: 원격 배포 및 정리 로직이 효율적으로 구성됨.다음 항목들이 잘 구성되었습니다:
- Config 파일 재배치: Nginx 설정을 정확한 경로(
/etc/nginx/conf.d/default.conf)로 이동- Nginx 검증 및 재시작:
nginx -t로 사전 검증 후 재시작 (무중단 배포)- Docker Compose 재시작:
down→up -d로 깔끔한 순환- 이미지 정리:
docker image prune -f로 이미지 제거 및 로컬 태그 이미지 최신 5개 유지- GHCR 정리: snok/container-retention-policy로 오래된 이미지 자동 삭제
특히 로컬(라인 122–129)과 GHCR(라인 135–144) 양쪽에서 정리 정책을 일관되게 적용(최신 5개 유지)하는 것이 스토리지 효율성과 유지보수성 면에서 좋습니다.
70-81: Deploy 키 파일명 오류.라인 72에서
deploy_key.pem을 생성하고 있으나, 라인 85의 SSH 명령어에서deploy_key_ssh.pem을 참조하고 있습니다. 이는 파일을 찾을 수 없는 오류로 인해 배포가 실패합니다.라인 85를 다음과 같이 수정하세요:
- ssh -i deploy_key_ssh.pem \ + ssh -i deploy_key.pem \Likely an incorrect or invalid review comment.
whqtker
left a comment
There was a problem hiding this comment.
제가 남긴 리뷰들에 대해서 해소가 되어서 approve하겠습니다 !
다른 분들까지 approve되면 머지 진행해주시면 될 거 같습니다. 고생하셨어요 !!
…ening-cd-time # Conflicts: # src/main/resources/secret
* fix: yml 들여쓰기 수정 (#555) * fix: yml 들여쓰기 수정 * fix: jdk 변경 * refactor: 멘토 및 채팅 관련 API 응답 수정 (#537) * refactor: 멘토의 멘토링 조회 응답에서 mentoringId가 아니라 roomId를 포함하도록 * refactor: 파트너가 멘토인 경우 partnerId는 mentorId로 - AS IS: 멘토/멘티 모두 partnerId가 siteUserId - TO BE: 멘티: siteUserId, 멘토: mentorId * refactor: 응답의 senderId가 mentorId/siteUserId가 되도록 * refactor: senderId에 해당하는 chatParticipant가 없을 경우 예외 처리하는 로직 추가 * refactor: 메서드명에 맞게 시그니처 변경 * refactor: getChatMessages 메서드에서 응답으로 siteUserId를 넘겨주도록 - AS IS: mentorId(mentor) / siteUserId(mentee) - TO BE: siteUserId(all) * refactor: 헬퍼 메서드로 메서드 복잡성을 분산한다 * refactor: getChatPartner 메서드의 응답으로 siteUserId를 넘겨주도록 - AS IS: mentorId(mentor) / siteUserId(mentee) - TO BE: siteUserId(all) * refactor: CD 성능 개선 (#552) * fix: deprecated된 base image를 eclipse-temurin:17-jdk로 변경 * refactor: scp 파일 전송하는 방식에서 GHCR로 push/pull하도록 변경 * fix: GHCR image 제거시 Org의 GITHUB_TOKEN 사용하도록 변경 * refactor : scp 파일 전송하는 방식에서 GHCR로 push/pull하도록 prod-cd.yml과 docker-compose.prod.yml 변경 * fix: prod 인스턴스 old image 이름 통일 * fix: prod-cd.yml StrictHostKeyChecking 옵션 문법 오류 수정 * fix: prod-cd.yml StrictHostKeyChecking 옵션 문법 오류 수정 * fix: dev-cd.yml Old images 정리 작업 중 이미지 이름 불일치 문제 해결 * chore: 마지막 줄 개행 추가 * chore: 마지막 줄 개행 추가 * feat: stage 인스턴스에 대한 최신 이미지 5개 유지 기능 및 old 이미지 제거 기능 추가 * chore: 중복된 환경변수 지정 제거 * chore: 중복된 pem키 생성 로직 제거 * fix: 잘못된 pem키 이름 수정 * refactor: 원격 호스트에서 pull할 경우, 최소 권한으로 실행하도록 Github App으로 임시토큰 발급하도록 수정 * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 (#565) * fix: GitHub app token permission 문제 해결 (#566) * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정 * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정 * fix: Github App이 발행한 임시 토큰에 대해 Contents 읽기 권한 추가 * fix: GitHub app token permission 문제 오류 해결 (#567) * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정 * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정 * fix: Github App이 발행한 임시 토큰에 대해 Contents 읽기 권한 추가 * fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가 * fix: GitHub app token permission이 repo 레벨에서 부여되는 문제 해결 (#568) * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정 * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정 * fix: Github App이 발행한 임시 토큰에 대해 Contents 읽기 권한 추가 * fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가 * fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가 * fix: GitHub app token permission 권한 오류 해결 (#569) * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정 * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정 * fix: Github App이 발행한 임시 토큰에 대해 Contents 읽기 권한 추가 * fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가 * fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가 * fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가 * test: fork repo의 작업 branch에서 해당 workflows가 실행되도록 임시 수정 * refactor: test용 설정 제거 * feat: claude.md 파일 추가 (#560) * fix : 동일 멘토 멘티 중복 신청 불가능하도록 수정 (#563) * fix : 동일 멘토 멘티 중복 신청 불가능하도록 수정 - UK 제약조건 추가 - flyway script 추가 - CustomException 추가 - Service 로직 수정 - Test code 추가 * fix : column명 오류 수정 - column명 camelCase -> snake_case로 변경 * fix : column명 오류 수정 - column명 name으로 명시 * fix: GitHub app token permission 권한 오류 해결 (#570) * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정 * fix: Github App이 발행한 임시 토큰에 대해 읽기 권한 명시 문법 오류 수정 * fix: Github App이 발행한 임시 토큰에 대해 Contents 읽기 권한 추가 * fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가 * fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가 * fix: Github App이 발행한 임시 토큰에 대해 조직 레벨에서 읽기 권한 추가 * test: fork repo의 작업 branch에서 해당 workflows가 실행되도록 임시 수정 * refactor: test용 설정 제거 * fix: docker login username 불일치 문제 * refactor: 최소권한 원칙 적용을 위한 Action Job 분리 * refactor: 필요없는 주석 제거 * fix: GHCR 정리 권한 PAT로 해결 (#573) * feat: 지원서가 APPROVED 인 유저의 멘토 생성 기능 추가 (#562) * feat: 지원서가 APPROVED 인 유저의 멘토 생성 기능 추가 * refactor: submitMentorApplication 메서드의 멘토 지원 유효 검증 부분을 메서드로 추출 * refactor: MentorMyPage 생성, 수정 부분의 channel 생성, 업데이트 부분 중복 제거 * test: Mentor 생성 관련 테스트 추가 * fix: 코드래빗 리뷰 적용 * refactor: 멘토 생성 시 channelRequest가 null 일 떄 예외 처리 * feat: MentorApplicationRequest 필드에 유효성 어노테이션 추가 * test: 채널 검색 시 siteUserId로 조회하는 문제 해결 * fix: 리뷰 수정사항 적용 * fix: 파일 끝에 개행 추가 * refactor: 멘토 생성 메서드에서 siteUser의 검증 제외 * refactor: dto 단에서 채널 리스트 null 검증 * feat: MentorApplication에 termId 추가 flyway 스크립트 추가 * fix: flyway 버전 충돌 해결 * feat: 어드민 멘토 승격 요청 페이징 조회 기능 추가 (#576) * feat: 어드민 멘토 지원서 페이징 조회 기능 추가 * feat: mentor/repository 패키지에 custom 패키지 추가 - custom 패키지에 페이징 조회를 책임지는 MentorApplicationFilterRepository 추가 - MentorApplicationSearchCondition 에서 넘긴 keyword 기반으로 닉네임, 권역, 나라, 학교명으로 필터링 검색 기능 추가 - MentorApplicationSearchCondition 에서 넘긴 mentorApplicationStatus 기반으로 승인, 거절, 진행중 으로 필터링 기능 추가 * test: 어드민 멘토 지원서 페이징 조회 테스트 추가 * feat: MentorApplication 엔티티에 approved_at 필드 추가 flyway 스크립트 작성 * fix: 파일 끝에 개행 추가 * refactor: 페이징 조회 시 count 쿼리에 불필요한 조인 막기 * fix: 코드래빗 리뷰 적용 * fix: flyway V39 스크립트 파일명 수정 * test: 테스트 코드 오류 수정, 검증 추가 * test: 기대하는 값이랑 다른 테스트 응답을 수정합니다 * feat: 어드민 멘토 승격 지원서 승인/거절 기능, 상태 별 지원서 개수 조회 기능 추가 (#577) * feat: 어드민 멘토 승격 지원서 승인/거절 기능 추가 * test: 어드민 멘토 지원서 승인/거절 테스트 추가 * feat: 멘토 지원서 상태별 개수 조회 기능 추가 * test: 멘토 지원서 상태별 개수 조회 테스트 추가 * fix: 대학이 선택되지 않은 멘토 지원서 승인 시 예외 발생하도록 수정 * refactor: 리뷰 내용 반영 * refactor: MENTOR_APPLICATION_ALREADY_CONFIRM -> MENTOR_APPLICATION_ALREADY_CONFIRMED 로 수정 * refactor: 멘토 지원서 거절 사유 관련하여 기획에 명시되지 않은 길이 제한 제거 * refactor: 리뷰 적용 * refactor: 변수명, 필드명 일관성 맞추기 * test: assertAll 적용 * feat: region 관련 관리 기능 추가 (#561) * feat: 지역 생성 기능 구현 (AdminRegion) 지역을 생성하는 기능을 구현했습니다: - AdminRegionCreateRequest: 지역 생성 요청 DTO - AdminRegionResponse: 지역 응답 DTO - AdminRegionService.createRegion(): 중복 검사를 포함한 지역 생성 로직 - AdminRegionController.createRegion(): HTTP POST 엔드포인트 중복 검사: - 지역 코드 중복 확인 - 한글명 중복 확인 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * feat: 지역 수정/삭제/조회 기능 구현 및 테스트 추가 (AdminRegion) 지역 관리 기능을 완성했습니다: 구현 기능: - AdminRegionUpdateRequest: 지역 수정 요청 DTO - AdminRegionService.updateRegion(): 한글명 중복 검사를 포함한 지역 수정 - AdminRegionService.deleteRegion(): 지역 삭제 - AdminRegionService.getAllRegions(): 전체 지역 조회 - AdminRegionController: 수정/삭제/조회 HTTP 엔드포인트 테스트 코드 (AdminRegionServiceTest): - CREATE: 정상 생성, 코드 중복, 한글명 중복 테스트 - UPDATE: 정상 수정, NOT_FOUND, 중복 한글명, 동일 한글명 테스트 - DELETE: 정상 삭제, NOT_FOUND 테스트 - READ: 빈 목록, 전체 조회 테스트 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: 지역 관리 관련 에러코드 추가 (ErrorCode) 지역 관리 기능에 필요한 에러코드를 추가했습니다: - REGION_NOT_FOUND: 존재하지 않는 지역 - REGION_ALREADY_EXISTS: 이미 존재하는 지역 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: jpa 오류 수정 * refactor: 코드리뷰 반영 --------- Co-authored-by: Claude <noreply@anthropic.com> * fix: config.alloy 파일 경로 불일치 문제 해결 (#586) * fix: config.alloy 파일 경로 불일치 문제 해결 * refactor: docker-compose를 수정하는게 아닌 cd.yml의 경로를 수정하여 해결 * feat: 소셜 로그인 사용자는 비밀번호 변경을 할 수 없다. (#582) * feat: 소셜 로그인 사용자는 비밀번호 변경을 할 수 없도록 * test: 소셜 로그인 사용자 비밀번호 변경 관련 테스트 코드 작성 * chore: 컨벤션에 맞게 메서드명 변경 - ~~ 예외가 발생한다 * chore: 충돌 해결 * fix: Upgrade 헤더 유무에 따라 Connection 헤더의 값을 동적으로 설정하도록 (#581) * fix: Upgrade 헤더 유무에 따라 Connection 헤더의 값을 동적으로 설정하도록 - Upgrade 헤더가 존재하면(e.g. WebSocket) upgrade로 설정 - Upgrade 헤더가 존재하지 않으면 keep-alive로 설정 * chore: 서브모듈 업데이트 * feat: 멘토 지원서 대학교 매핑 기능, 대학 선택 상태 페이징 조건 추가 (#583) * feat: 멘토 지원서 검색 조건에 UniversitySelectType 추가 * feat: 어드민 멘토 지원서 페이징 조회 응답에 UniversitySelectType 추가 * test: 멘토 지원서 조회 테스트 추가 - test: UniversitySelectType 기반 페이징 조회 테스트 추가 * feat: 멘토 지원서에 대학 매핑 기능 추가 * test: 멘토 지원서 대학 매핑 테스트 추가 * refactor: 의미 없는 import 제거 * refactor: 리뷰 내용 반영 * refactor: 개행 및 공백 추가 * refactor: pathVariable 네이밍을 kebab-case 로 통일 * refactor: Service 레이어의 검증 로직을 도메인으로 이동 * refactor: PENDING 상태 및 OTHER 타입 검증을 도메인 메서드로 관리 * refactor: assignUniversity() 호출 전 검증 책임을 도메인 엔티티에 위임 * test : assertAll 로 검증 그룹화 * refactor: 스프링 부트 앱 외의 사이드 인프라 배포 과정을 분리 (#592) * refactor: dev 환경에서의 side-infra 배포 과정 분리 * refactor: prod 환경에서의 side-infra 배포 과정 분리 * refactor: docker-compose 가 실행되고 있지 않아도 스크립트가 실패하지 않게 변경 * fix: docker compose up 시에 사용할 환경변수 중 누락된 변수를 추가 * fix: S3 이름 불일치 문제 해결 (#594) * fix: s3 이름 불일치 문제 해결 * fix: s3와의 연동된 cloudfront URL로 수정 * refactor: 분리한 사이드 인프라에 대해서 필요없는 파일 정리 (#596) * test: flyway 스크립트를 검증하는 테스트 코드 작성 (#588) * test: flyway 스크립트를 검증하는 테스트 코드 작성 * fix: DirtiesContext 어노테이션을 통해 기존 컨텍스트를 폐기하도록 - 새로운 MySQL 환경에서 마이그레이션이 이루어지도록 수정 * fix: flyway 검증용의 별도의 MySQL 컨테이너를 사용하도록 * chore: 테스트 의도를 쉽게 이해할 수 있도록 주석 추가 * chore: 명시적으로 컨테이너를 시작하도록 - 또한 MySQLTestContainer 코드와 유사한 컨벤션을 가지도록 수정 * refactor: 게시글 조회 응답에 댓글 deprecated 여부 포함하도록 (#599) * feat: 유저의 멘토 지원서 신청 이력 조회 기능 추가 (#603) * feat: 유저의 멘토 지원 이력 조회 기능 추가 * refactor: 매개변수 타입 통일 * refactor: long 타입을 Long 으로 수정 * test: 멘토 지원서 이력 조회 테스트 추가 * test: MentorApplicationFixtureBuilder 에 rejectedReason 필드 및 빌더 메서드 추가 * refactor: 리뷰 사항 적용 * test: 멘토 지원서 이력 조회 에서 user와 university 재사용 * refactor: 긴 uri 를 짧게 수정 * refactor: 서브모듈 해시값 되돌리기 * refactor: 개행 지우기 * refactor: applicationOrder 자료형을 long 으로 수정 * fix: applicationOrder 를 int 자료형으로 처리하도록 복구 - 순서를 나타내고, 해당 값이 21억을 넘길 수 없다 판단하여 더 적합한 int 자료형으로 복구 * test: long type 을 기대하던 테스트 에러 해결 * fix: 탈퇴한 사용자가 물리적 삭제가 되지 않았던 문제를 해결한다 (#574) * refactor: FK에 ON DELETE CASCADE 옵션 추가 * refactor: 삭제 메서드로 사용자 연관 데이터를 삭제하도록 * feat: 어드민 유저 차단 기능 추가 (#604) * feat: 어드민 차단 기능 * test: 어드민 차단 기능 * feat: API 성능 로깅, 쿼리 별 메트릭 전송 추가 (#602) * feat: HTTP 요청/응답 로깅 필터 구현 - traceId 기반 요청 추적 - 요청/응답 로깅 - CustomExceptionHandler와 중복 로깅 방지 - Actuator 엔드포인트 로깅 제외 * feat: ExceptionHandler에 중복 로깅 방지 플래그 및 userId 로깅 추가 * feat: API 수행시간 로깅 인터셉터 추가 * feat: ApiPerf 인터셉터, Logging 필터 빈 등록 * refactor: logback 설정 변경 - info, warn, error, api_perf 로 로그 파일 분리해서 관리 * feat: 쿼리 별 수행시간 메트릭 모니터링 추가 * feat: 데이터소스 프록시 의존성 및 config 파일 추가 * feat: 데이터 소스 프록시가 metric을 찍을 수 있도록 listener 클래스 추가 * feat: 요청 시 method, uri 정보를 listener에서 활용하기 위해 RequestContext 및 관련 interceptor 추가 * refactor: 비효율적인 Time 빌더 생성 개선 - Time.builder 를 사용하면 매번 빌더를 생성하여 비효율적인 문제를 meterRegistry.timer 방식으로 해결 * feat: 로깅을 위해 HttpServeletRequest 속성에 userId 추가 * refactor: logback 설정 중 local은 console만 찍도록 수정 * refactor: FILE_PATTERN -> LOG_PATTERN 으로 수정 * test: TokenAuthenticationFilter에서 request에 userId 설정 검증 추가 - principal 조회 예외를 막기 위해 siteUserDetailsService given 추가 * refacotr: 코드 래빗 리뷰사항 반영 * test: 중복되는 테스트 제거 * refactor: 사용하지 않는 필드 제거 * refactor: 리뷰 내용 반영 * refactor: ApiPerformanceInterceptor에서 uri 정규화 관련 코드 제거 * refactor: ApiPerformanceInterceptor에서 if-return 문을 if-else 문으로 수정 * refactor: 추가한 interceptor 의 설정에 actuator 경로 무시하도록 셋팅 * refactor: 중복되는 의존성 제거 * refactor: 로깅 시 민감한 쿼리 파라미터 마스킹 - EXCLUDE_QUERIES 에 해당하는 쿼리 파라미터 KEY 값의 VALUE 를 masking 값으로 치환 * refactor: 예외 처리 후에도 Response 로그 찍도록 수정 * refactor: CustomExceptionHandler 원상복구 - Response 로그를 통해 user를 추적할 수 있으므로 로그에 userId 를 추가하지 않습니다 * refactor: 리뷰 사항 반영 * refactor: RequestContext 빌더 제거 * refactor: RequestContextInterceptor import 수정 * refactor: logback yml 파일에서 timestamp 서버 시간과 동일한 규격으로 수정 * refactor: ApiPerformanceInterceptor 에서 동일 내용 로그 중복으로 찍는 문제 수정 * fix: decode를 두 번 하는 문제 수정 * test: 로깅 관련 filter, interceptor 테스트 추가 * refactor: 코드래빗 리뷰사항 반영 * test: contains 로 비교하던 검증 로직을 isEqualTo 로 수정 * test: preHandle 테스트 에서 result 값을 항상 검증 * refactor: 단위테스트에 TestContainer 어노테이션 제거 * fix: conflict 해결 * fix: docker-compose 충돌 해결 (#610) * chore: release github action 임의 실행 추가 * refactor: 기본 추천 대학 후보 추가 (#161) * fix: config.alloy 경로 수정 * hotfix: 모의지원 현황 어드민 권한 제거 * hotfix: import 제거 * chore: 서브모듈 해시 업데이트 (#611)


관련 이슈
작업 내용
jar파일을 포함,nginx와alloy등의 설정 파일을ssh copy(scp)명령으로 전송 이후, 원격 호스트에서build하고docker-compose를 실행하는 방식을 사용해왔습니다.GHCR(Github Container Registry)를 사용하여 Github Action에서 이미지 빌드 이후,GHCR로 push/원격호스트에서 pull하는 방식으로docker-compose를 실행하도록 리팩토링했습니다.3분이었지만, 현재는 평균2분 15초로25%단축시킨 결과가 나왔습니다. (테스트 결과는 아래 첨부파일에 올려두겠습니다.)이미지:날짜-시간방식으로 태그가 되어 있는 상태입니다. 하지만 prod 인스턴스는 릴리즈 버전으로 관리될 수 있기에 여러분의 의견을 듣고 내용 반영하여 추가 commit 올리겠습니다!특이 사항
base image로openjdk:17-jdk를 사용해왔지만, 해당 base image가 deprecated되어 공식 대체 이미지인eclipse-temurin:17-jdk로 변경하였습니다.리뷰 요구사항 (선택)
날짜-시간으로 설정해두었습니다.첨부파일(테스트 결과)